
//--xuezhen--

`include "defines.v"

module cpu(
    input                               clock,
    input                               reset,
    input                               axi_done,
    
    //if
    output                              if_valid,
    output [63:0]                       if_addr,
    output [1:0]                        if_size,

    //input                               if_ready,
    input  [63:0]                       if_data_read,
    input  [1:0]                        if_resp,

    //mem
    output reg mem_valid,
    output reg [63:0]  mem_addr,
    output reg [1:0] mem_size,
    output reg mem_load_en,
    output reg mem_save_en,
    output reg [63:0] mem_data,

    input [63:0] mem_data_read,
    input [1:0] mem_resp,

    //putch
    output putch_en,
    output [7:0]chara

);


////////////////CLINT/MMIO////////////////
clint clint(
  .clk(clock),
	.rst(reset),
  //input 
  .mem_valid(mem_valid_mmio),
  .mem_addr(mem_addr_mmio),
  .mem_size(mem_size_mmio),
  .mem_load_en(mem_load_en_mmio),
  .mem_save_en(mem_save_en_mmio),
  .mem_data(mem_data_mmio),
  //output 
  .clint_data_read(clint_data_read_mmio),
  //.clint_done(clint_done_mmio),

  .clint_raise_interruption(clint_raise_interruption)
);

//from mem_stage
wire mem_valid_origin;
wire [63:0] mem_addr_origin;
wire [1:0] mem_size_origin;
wire mem_load_en_origin;
wire mem_save_en_origin;
wire [63:0]mem_data_origin;
reg [63:0]data_loaded_origin;
reg data_valid_origin;

//to clint
reg mem_valid_mmio;
reg [63:0] mem_addr_mmio;
reg [1:0] mem_size_mmio;
reg mem_load_en_mmio;
reg mem_save_en_mmio;
reg [63:0]mem_data_mmio;
wire [63:0]clint_data_read_mmio;
reg clint_done_mmio;

//to axi
//...

//crossbar
reg mmio_valid;
always @(*) begin
  if ((mem_valid_origin == 1'b1) && ((mem_addr_origin == 64'h200bff8)||(mem_addr_origin == 64'h2004000))) begin   //if MMIO
    mem_valid_mmio = mem_valid_origin;
    mem_addr_mmio = mem_addr_origin;
    mem_size_mmio = mem_size_origin;
    mem_load_en_mmio = mem_load_en_origin;
    mem_save_en_mmio = mem_save_en_origin;
    mem_data_mmio = mem_data_origin;

    data_loaded_origin = clint_data_read_mmio;
    data_valid_origin = 1'b1;

    mem_valid = 0;
    mem_addr = 0;
    mem_size = 0;
    mem_load_en = 0;
    mem_save_en = 0;
    mem_data = 0;

    mmio_valid = 1'b1;
  end
  else begin                                                          //if AXI
    mem_valid = mem_valid_origin;
    mem_addr = mem_addr_origin;
    mem_size = mem_size_origin;
    mem_load_en = mem_load_en_origin;
    mem_save_en = mem_save_en_origin;
    mem_data = mem_data_origin;

    data_loaded_origin = mem_data_read;
    data_valid_origin = axi_done;

    mem_valid_mmio = 0;
    mem_addr_mmio = 0;
    mem_size_mmio = 0;
    mem_load_en_mmio = 0;
    mem_save_en_mmio = 0;
    mem_data_mmio = 0;
    
    mmio_valid = 1'b0;
  end
end


////////////////putch////////////////
wire [7:0]a0;
//wire [7:0]ch;
//assign ch = (putch_en == 1'b1)? a0 : 0;

////////////////axi_stall////////////////
wire axi_stall;
assign axi_stall = ((mem_valid || if_valid) && (axi_done != 1'b1));   //stall when there are axi requests and the task is not done

////////////////stall////////////////
reg stall;
always @(*) begin
  if ((rs1_r_ena == 1'b1) && (rs1_r_addr == exe_rd_w_addr) && (exe_rd_w_ena == 1'b1)) begin  
    stall = 1'b1;
  end
  else if ((rs1_r_ena == 1'b1) && (rs1_r_addr == mem_rd_w_addr) && (mem_rd_w_ena == 1'b1)) begin
    stall = 1'b1;
  end
  else if ((rs2_r_ena == 1'b1) && (rs2_r_addr == exe_rd_w_addr) && (exe_rd_w_ena == 1'b1)) begin  
    stall = 1'b1;
  end
  else if ((rs2_r_ena == 1'b1) && (rs2_r_addr == mem_rd_w_addr) && (mem_rd_w_ena == 1'b1)) begin
    stall = 1'b1;
  end
  else if (((id_ecall == 1'b1)||(id_mret == 1'b1))&&((exe_csr_ena==1'b1)||(mem_csr_ena==1'b1)||(wb_csr_w_ena==1'b1)||(wb_csr_r_ena==1'b1)))begin  //if decoding a ecall or mret but there are csr inst not been finished in mem/exe/wb
    stall = 1'b1;
  end
  //else if ((exe_ecall == 1'b1)||(exe_mret ==1'b1)||(mem_ecall == 1'b1)||(mem_mret == 1'b1)) begin
    //stall = 1'b1;
  //end
  else if ((ok_to_insert == 1'b1)&&((exe_csr_ena==1'b1)||(mem_csr_ena==1'b1)||(wb_csr_r_ena==1'b1)||(wb_csr_w_ena==1'b1)||(exe_ecall==1'b1)||(exe_mret==1'b1)||(mem_ecall==1'b1)||(mem_mret==1'b1)||(wb_ecall==1'b1)||(wb_mret==1'b1))) begin  //current inst in id stage is ok to insert interruption, but there are csr inst not been finished in mem/exe/wb
    stall = 1'b1;
  end
  else begin
    stall = 1'b0;
  end
end

////////////////id<-->reg////////////////
// id_stage -> regfile
wire rs1_r_ena;
wire [4 : 0]rs1_r_addr;
wire rs2_r_ena;
wire [4 : 0]rs2_r_addr;
// regfile -> id_stage
wire [`REG_BUS] r_data1;
wire [`REG_BUS] r_data2;


////////////////difftest<-->reg////////////////
// regfile -> difftest
wire [`REG_BUS] regs[0 : 31];

////////////////flush////////////////
wire flush;
assign flush = exe_jump;
//wire flush_exception;
//assign flush_exception = ecall_en || mret_en;
//assign flush_exception = 0;

////////////////IF_stage_PC_destination////////////////
wire exe_jump;
wire jump_en;
assign jump_en = exe_jump;
wire [`REG_BUS]exe_pc_dest;
wire [`REG_BUS]mtvec_dest;
wire [`REG_BUS]mepc_dest;
reg [`REG_BUS]pc_dest;
always @(*) begin
  if (exe_ecall==1'b1) begin
    pc_dest = mtvec_dest;
  end
  else if (exe_mret==1'b1) begin
    pc_dest = mepc_dest;
  end
  else if (exe_time_intr_firstdetect==1'b1)begin
    pc_dest = mtvec_dest;
  end
  else begin
    pc_dest = exe_pc_dest;
  end
end

////////////////PC_RESET////////////////
//parameter PC_START_RESET = `PC_START - 4;
parameter PC_START_RESET = `PC_START;



////////////////if_stage////////////////
if_stage If_stage(
  .clk(clock),
  .rst(reset),

  .stall(stall),
  .axi_stall(axi_stall),
  .jump_en(jump_en),
  .pc_dest(pc_dest),

  //from axi
  .inst_i(if_data_read[31:0]),
  
  //to axi
  .inst_addr(if_addr),
  .inst_ena(if_valid),
  .inst_size(if_size),

  .pc_o(if_pc),
  .inst_o(if_inst)
);

//if_stage_out
wire [31:0] if_inst;
wire [`REG_BUS] if_pc;
wire [`REG_BUS] if_inst_addr;
wire if_inst_ena;

//if_stage -> id_stage
reg [31:0] if_id_inst;
reg [`REG_BUS] if_id_pc;
always @(posedge clock) begin
  if (reset == 1'b1)  begin
    if_id_inst <= 32'b0;
    //if_id_pc <= `ZERO_WORD;
    if_id_pc <= PC_START_RESET;
  end
  else if (axi_stall == 1'b1) begin
    if_id_inst <= if_id_inst;
    if_id_pc <= if_id_pc;
  end
  else if (flush == 1'b1) begin
    if_id_inst <= 32'b0;
    //if_id_pc <= `ZERO_WORD;
    if_id_pc <= PC_START_RESET;
  end
  else if (stall == 1'b1) begin
      if_id_inst <= if_id_inst;
      if_id_pc <= if_id_pc;
  end
  else begin
    if_id_inst <= if_inst;
    if_id_pc <= if_pc;
  end

end



////////////////id_stage////////////////
id_stage Id_stage(
  //.clk(clk),
  .rst(reset),
  .inst_i(if_id_inst),
  .pc_i(if_id_pc),

  //from reg
  .rs1_data(r_data1),
  .rs2_data(r_data2),
  .a0_i(a0),

  //interruption
  .time_intr_confirm_i(time_interruption_confirmation),
  
  //to reg
  .rs1_r_ena(rs1_r_ena),
  .rs1_r_addr(rs1_r_addr),
  .rs2_r_ena(rs2_r_ena),
  .rs2_r_addr(rs2_r_addr),
  //pass
  .rd_w_ena(id_rd_w_ena),
  .rd_w_addr(id_rd_w_addr),
  .inst_type(id_inst_type),
  .alu_opcode(id_alu_opcode),
  .alu_single_word(id_alu_single_word),
  .op1(id_op1),
  .op2(id_op2),
  .l_mem(id_l_mem),
  .s_mem(id_s_mem),
  .datasize(id_datasize),
  .unsigned_load(id_unsigned_load),
  .rs1_data_o(id_rs1_data),
  .rs2_data_o(id_rs2_data),
  .branch_type(id_branch_type),
  .jump_type(id_jump_type),
  .inst_o(id_inst),   //for difftest
  .pc_o(id_pc),
  .csr_addr(id_csr_addr),
  .csr_ena(id_csr_ena),
  .csr_op(id_csr_op),
  .csr_mode(id_csr_mode),
  .putch_en(id_putch_en),
  .a0_o(id_a0),
  .ecall(id_ecall),
  .mret(id_mret)
  //.time_intr_o(id_time_intr)
);


// id_stage_out
wire id_rd_w_ena;
wire [4 : 0]id_rd_w_addr;
wire [4 : 0]id_inst_type;
wire [7 : 0]id_alu_opcode;
wire id_alu_single_word;
wire [`REG_BUS]id_op1;
wire [`REG_BUS]id_op2;
wire id_l_mem;
wire id_s_mem;
wire [1:0]id_datasize;
wire id_unsigned_load;
wire [`REG_BUS]id_rs1_data;
wire [`REG_BUS]id_rs2_data;
wire [2:0]id_branch_type;
wire [1:0]id_jump_type;
wire [31:0] id_inst;
wire [`REG_BUS]id_pc;
wire [11:0]id_csr_addr;
wire id_csr_ena;
wire [`REG_BUS]id_csr_op;
wire [1:0]id_csr_mode;
wire id_putch_en;
wire [7:0]id_a0;
wire id_ecall;
wire id_mret;
//wire id_time_intr;


// id_stage -> exe_stage
reg id_exe_rd_w_ena;
reg [4 : 0]id_exe_rd_w_addr;
reg [4 : 0]id_exe_inst_type;
reg [7 : 0]id_exe_alu_opcode;
reg id_exe_alu_single_word;
reg [`REG_BUS]id_exe_op1;
reg [`REG_BUS]id_exe_op2;
reg id_exe_l_mem;
reg id_exe_s_mem;
reg [1:0]id_exe_datasize;
reg id_exe_unsigned_load;
reg [`REG_BUS]id_exe_rs1_data;
reg [`REG_BUS]id_exe_rs2_data;
reg [2:0]id_exe_branch_type;
reg [1:0]id_exe_jump_type;
reg [31:0]id_exe_inst;
reg [`REG_BUS]id_exe_pc;
reg [11:0]id_exe_csr_addr;
reg id_exe_csr_ena;
reg [`REG_BUS]id_exe_csr_op;
reg [1:0]id_exe_csr_mode;
reg id_exe_putch_en;
reg [7:0]id_exe_a0;
reg id_exe_ecall;
reg id_exe_mret;
//reg id_exe_time_intr;

/*
always @(posedge clock) begin
  if (reset == 1'b1) begin
    id_exe_rd_w_ena <= 1'b0;
    id_exe_rd_w_addr<=5'b00000;
    id_exe_inst_type<=5'b00000;
    id_exe_alu_opcode<=8'b00000000;
    id_exe_alu_single_word <= 1'b0;
    id_exe_op1<=`ZERO_WORD;
    id_exe_op2<=`ZERO_WORD;
    id_exe_l_mem<=1'b0;
    id_exe_s_mem<=1'b0;
    id_exe_datasize<=2'b00;
    id_exe_unsigned_load<=1'b0; 
    id_exe_rs1_data<=`ZERO_WORD;
    id_exe_rs2_data<=`ZERO_WORD;
    id_exe_branch_type<=3'b000;
    id_exe_jump_type<=2'b00;
    id_exe_inst<=32'b0;
    id_exe_pc<=PC_START_RESET;
    id_exe_csr_addr<=12'b000000000000;
    id_exe_csr_ena<=1'b0;
    id_exe_csr_op<=`ZERO_WORD;
    id_exe_csr_mode<=2'b00;
    id_exe_putch_en<=1'b0;
    id_exe_a0<=8'b0;
    id_exe_ecall<=1'b0;
    id_exe_mret<=1'b0;
    //id_exe_time_intr<=1'b0;
  end
  else if (axi_stall == 1'b1) begin
    id_exe_rd_w_ena <= id_exe_rd_w_ena;
    id_exe_rd_w_addr<=id_exe_rd_w_addr;
    id_exe_inst_type<=id_exe_inst_type;
    id_exe_alu_opcode<=id_exe_alu_opcode;
    id_exe_alu_single_word <= id_exe_alu_single_word;
    id_exe_op1<=id_exe_op1;
    id_exe_op2<=id_exe_op2;
    id_exe_l_mem<=id_exe_l_mem;
    id_exe_s_mem<=id_exe_s_mem;
    id_exe_datasize<=id_exe_datasize;
    id_exe_unsigned_load<=id_exe_unsigned_load; 
    id_exe_rs1_data<=id_exe_rs1_data;
    id_exe_rs2_data<=id_exe_rs2_data;
    id_exe_branch_type<=id_exe_branch_type;
    id_exe_jump_type<=id_exe_jump_type;
    id_exe_inst<=id_exe_inst;
    id_exe_pc<=id_exe_pc;
    id_exe_csr_addr<=id_exe_csr_addr;
    id_exe_csr_ena<=id_exe_csr_ena;
    id_exe_csr_op<=id_exe_csr_op;
    id_exe_csr_mode<=id_exe_csr_mode;
    id_exe_putch_en<=id_exe_putch_en;
    id_exe_a0<=id_exe_a0;
    id_exe_ecall<=id_exe_ecall;
    id_exe_mret<=id_exe_mret;
    //id_exe_time_intr<=id_exe_time_intr;
  end
  else if ((stall == 1'b1) || (flush == 1'b1)) begin
    id_exe_rd_w_ena <= 1'b0;
    id_exe_rd_w_addr<=5'b00000;
    id_exe_inst_type<=5'b00000;
    id_exe_alu_opcode<=8'b00000000;
    id_exe_alu_single_word <= 1'b0;
    id_exe_op1<=`ZERO_WORD;
    id_exe_op2<=`ZERO_WORD;
    id_exe_l_mem<=1'b0;
    id_exe_s_mem<=1'b0;
    id_exe_datasize<=2'b00;
    id_exe_unsigned_load<=1'b0; 
    id_exe_rs1_data<=`ZERO_WORD;
    id_exe_rs2_data<=`ZERO_WORD;
    id_exe_branch_type<=3'b000;
    id_exe_jump_type<=2'b00;
    id_exe_inst<=32'b0;
    id_exe_pc<=PC_START_RESET;
    id_exe_csr_addr<=12'b000000000000;
    id_exe_csr_ena<=1'b0;
    id_exe_csr_op<=`ZERO_WORD;
    id_exe_csr_mode<=2'b00;
    id_exe_putch_en<=1'b0;
    id_exe_a0<=8'b0;
    id_exe_ecall<=1'b0;
    id_exe_mret<=1'b0;
    ///////////id_exe_time_intr<=1'b0;  // this interruption flag will not be flush unless reset
  end
  else begin
    id_exe_rd_w_ena <= id_rd_w_ena;
    id_exe_rd_w_addr<=id_rd_w_addr;
    id_exe_inst_type<=id_inst_type;
    id_exe_alu_opcode<=id_alu_opcode;
    id_exe_alu_single_word<=id_alu_single_word;
    id_exe_op1<=id_op1;
    id_exe_op2<=id_op2;
    id_exe_l_mem<=id_l_mem;
    id_exe_s_mem<=id_s_mem;
    id_exe_datasize<=id_datasize;
    id_exe_unsigned_load<=id_unsigned_load; 
    id_exe_rs1_data<=id_rs1_data;
    id_exe_rs2_data<=id_rs2_data;
    id_exe_branch_type<=id_branch_type;
    id_exe_jump_type<=id_jump_type;
    id_exe_inst<=id_inst;
    id_exe_pc<=id_pc;
    id_exe_csr_addr<=id_csr_addr;
    id_exe_csr_ena<=id_csr_ena;
    id_exe_csr_op<=id_csr_op;
    id_exe_csr_mode<=id_csr_mode;
    id_exe_putch_en<=id_putch_en;
    id_exe_a0<=id_a0;
    id_exe_ecall<=id_ecall;
    id_exe_mret<=id_mret;
    //id_exe_time_intr<=id_time_intr;
  end

end
*/


//time interruption state machine
reg time_intr_state;
reg id_exe_time_intr_firstdetect;
wire ok_to_insert;
assign ok_to_insert = ((time_interruption_confirmation == 1'b1) && (if_id_inst != 32'b0) && (if_id_pc != PC_START_RESET) && (id_ecall!=1'b1) && (id_mret!=1'b1) && (id_csr_ena!=1'b1)) ; //indicate that the current inst in id stage is ok to insert interruption
always @(posedge clock) begin
  if (reset == 1'b1) begin
    id_exe_rd_w_ena <= 1'b0;
    id_exe_rd_w_addr<=5'b00000;
    id_exe_inst_type<=5'b00000;
    id_exe_alu_opcode<=8'b00000000;
    id_exe_alu_single_word <= 1'b0;
    id_exe_op1<=`ZERO_WORD;
    id_exe_op2<=`ZERO_WORD;
    id_exe_l_mem<=1'b0;
    id_exe_s_mem<=1'b0;
    id_exe_datasize<=2'b00;
    id_exe_unsigned_load<=1'b0; 
    id_exe_rs1_data<=`ZERO_WORD;
    id_exe_rs2_data<=`ZERO_WORD;
    id_exe_branch_type<=3'b000;
    id_exe_jump_type<=2'b00;
    id_exe_inst<=32'b0;
    id_exe_pc<=PC_START_RESET;
    id_exe_csr_addr<=12'b000000000000;
    id_exe_csr_ena<=1'b0;
    id_exe_csr_op<=`ZERO_WORD;
    id_exe_csr_mode<=2'b00;
    id_exe_putch_en<=1'b0;
    id_exe_a0<=8'b0;
    id_exe_ecall<=1'b0;
    id_exe_mret<=1'b0;

    time_intr_state <= 1'b0;
    id_exe_time_intr_firstdetect<=1'b0;
  end
  else begin
    if (axi_stall == 1'b1) begin
      id_exe_rd_w_ena <= id_exe_rd_w_ena;
      id_exe_rd_w_addr<=id_exe_rd_w_addr;
      id_exe_inst_type<=id_exe_inst_type;
      id_exe_alu_opcode<=id_exe_alu_opcode;
      id_exe_alu_single_word <= id_exe_alu_single_word;
      id_exe_op1<=id_exe_op1;
      id_exe_op2<=id_exe_op2;
      id_exe_l_mem<=id_exe_l_mem;
      id_exe_s_mem<=id_exe_s_mem;
      id_exe_datasize<=id_exe_datasize;
      id_exe_unsigned_load<=id_exe_unsigned_load; 
      id_exe_rs1_data<=id_exe_rs1_data;
      id_exe_rs2_data<=id_exe_rs2_data;
      id_exe_branch_type<=id_exe_branch_type;
      id_exe_jump_type<=id_exe_jump_type;
      id_exe_inst<=id_exe_inst;
      id_exe_pc<=id_exe_pc;
      id_exe_csr_addr<=id_exe_csr_addr;
      id_exe_csr_ena<=id_exe_csr_ena;
      id_exe_csr_op<=id_exe_csr_op;
      id_exe_csr_mode<=id_exe_csr_mode;
      id_exe_putch_en<=id_exe_putch_en;
      id_exe_a0<=id_exe_a0;
      id_exe_ecall<=id_exe_ecall;
      id_exe_mret<=id_exe_mret;

      time_intr_state<=time_intr_state;
      id_exe_time_intr_firstdetect<=id_exe_time_intr_firstdetect;
    end
    else begin   //if not reset or axistall, begin
      //DEFAULT operation
      if ((stall == 1'b1) || (flush == 1'b1)) begin
        id_exe_rd_w_ena <= 1'b0;
        id_exe_rd_w_addr<=5'b00000;
        id_exe_inst_type<=5'b00000;
        id_exe_alu_opcode<=8'b00000000;
        id_exe_alu_single_word <= 1'b0;
        id_exe_op1<=`ZERO_WORD;
        id_exe_op2<=`ZERO_WORD;
        id_exe_l_mem<=1'b0;
        id_exe_s_mem<=1'b0;
        id_exe_datasize<=2'b00;
        id_exe_unsigned_load<=1'b0; 
        id_exe_rs1_data<=`ZERO_WORD;
        id_exe_rs2_data<=`ZERO_WORD;
        id_exe_branch_type<=3'b000;
        id_exe_jump_type<=2'b00;
        id_exe_inst<=32'b0;
        id_exe_pc<=PC_START_RESET;
        id_exe_csr_addr<=12'b000000000000;
        id_exe_csr_ena<=1'b0;
        id_exe_csr_op<=`ZERO_WORD;
        id_exe_csr_mode<=2'b00;
        id_exe_putch_en<=1'b0;
        id_exe_a0<=8'b0;
        id_exe_ecall<=1'b0;
        id_exe_mret<=1'b0;
        ///////////id_exe_time_intr<=1'b0;  // this interruption flag will not be flush unless reset
      end
      else begin
        id_exe_rd_w_ena <= id_rd_w_ena;
        id_exe_rd_w_addr<=id_rd_w_addr;
        id_exe_inst_type<=id_inst_type;
        id_exe_alu_opcode<=id_alu_opcode;
        id_exe_alu_single_word<=id_alu_single_word;
        id_exe_op1<=id_op1;
        id_exe_op2<=id_op2;
        id_exe_l_mem<=id_l_mem;
        id_exe_s_mem<=id_s_mem;
        id_exe_datasize<=id_datasize;
        id_exe_unsigned_load<=id_unsigned_load; 
        id_exe_rs1_data<=id_rs1_data;
        id_exe_rs2_data<=id_rs2_data;
        id_exe_branch_type<=id_branch_type;
        id_exe_jump_type<=id_jump_type;
        id_exe_inst<=id_inst;
        id_exe_pc<=id_pc;
        id_exe_csr_addr<=id_csr_addr;
        id_exe_csr_ena<=id_csr_ena;
        id_exe_csr_op<=id_csr_op;
        id_exe_csr_mode<=id_csr_mode;
        id_exe_putch_en<=id_putch_en;
        id_exe_a0<=id_a0;
        id_exe_ecall<=id_ecall;
        id_exe_mret<=id_mret;
        //id_exe_time_intr<=id_time_intr;
      end


      //INTERRUPT operation, overwrite some reg
      case( time_intr_state )
      1'b0: begin
        if (ok_to_insert == 1'b1) begin
          if ((axi_stall != 1'b1)&&((stall != 1'b1) && (flush != 1'b1))) begin
            //overwrite some reg, when insert a interruption
            id_exe_rd_w_ena <= 1'b0;
            id_exe_rd_w_addr<=5'b00000;
            id_exe_inst_type<=5'b00000;
            id_exe_alu_opcode<=8'b00000000;
            id_exe_alu_single_word <= 1'b0;
            id_exe_op1<=`ZERO_WORD;
            id_exe_op2<=`ZERO_WORD;
            id_exe_l_mem<=1'b0;
            id_exe_s_mem<=1'b0;
            id_exe_datasize<=2'b00;
            id_exe_unsigned_load<=1'b0; 
            id_exe_rs1_data<=`ZERO_WORD;
            id_exe_rs2_data<=`ZERO_WORD;
            id_exe_branch_type<=3'b000;
            id_exe_jump_type<=2'b00;
            //id_exe_inst<=32'b0;
            //id_exe_pc<=PC_START_RESET;
            id_exe_csr_addr<=12'b000000000000;
            id_exe_csr_ena<=1'b0;
            id_exe_csr_op<=`ZERO_WORD;
            id_exe_csr_mode<=2'b00;
            id_exe_putch_en<=1'b0;
            id_exe_a0<=8'b0;
            id_exe_ecall<=1'b0;
            id_exe_mret<=1'b0;

            id_exe_time_intr_firstdetect <= ok_to_insert;
            time_intr_state <= 1'b1;  //indicate that already sent a time instrruption in the pipeline
          end
          else begin
            id_exe_time_intr_firstdetect <= 1'b0;
          end
        end
        else begin
          id_exe_time_intr_firstdetect <= 1'b0;
        end
      end
      1'b1: begin
        id_exe_time_intr_firstdetect <= 1'b0;
        if (time_interruption_confirmation == 1'b0) begin
          time_intr_state <= 1'b0;   // wait for the next interruption
        end
      end
      endcase     
    end
  end
end



////////////////exe_stage////////////////
exe_stage Exe_stage(
  .rst(reset),
  .rd_w_ena_i(id_exe_rd_w_ena),
  .rd_w_addr_i(id_exe_rd_w_addr),
  .inst_type_i(id_exe_inst_type),
  .alu_opcode(id_exe_alu_opcode),
  .alu_single_word(id_exe_alu_single_word),
  .op1(id_exe_op1),
  .op2(id_exe_op2),
  .l_mem_i(id_exe_l_mem),
  .s_mem_i(id_exe_s_mem),
  .datasize_i(id_exe_datasize),
  .unsigned_load_i(id_exe_unsigned_load),
  .rs1_data_i(id_exe_rs1_data),
  .rs2_data_i(id_exe_rs2_data),
  .branch_type(id_exe_branch_type),
  .jump_type(id_exe_jump_type),
  .inst_i(id_exe_inst),
  .pc_i(id_exe_pc),
  .csr_addr_i(id_exe_csr_addr),
  .csr_ena_i(id_exe_csr_ena),
  .csr_op_i(id_exe_csr_op),
  .csr_mode_i(id_exe_csr_mode),
  .putch_en_i(id_exe_putch_en),
  .a0_i(id_exe_a0),
  .ecall_i(id_exe_ecall),
  .mret_i(id_exe_mret),
  //.time_intr_i(id_exe_time_intr),
  .time_intr_firstdetect_i(id_exe_time_intr_firstdetect),


  //result to out
  .alu_result_o(exe_alu_result),
  .jump(exe_jump),    //enable jump in pc!
  .pc_dest(exe_pc_dest),
  //.next_pc(exe_next_pc),
  
  //pass
  .inst_type_o(exe_inst_type),
  .rd_w_ena_o(exe_rd_w_ena),
  .rd_w_addr_o(exe_rd_w_addr),
  .l_mem_o(exe_l_mem),
  .s_mem_o(exe_s_mem),
  .datasize_o(exe_datasize),
  .unsigned_load_o(exe_unsigned_load),
  .rs2_data_o(exe_rs2_data),
  .inst_o(exe_inst),
  .pc_o(exe_pc),
  .csr_addr_o(exe_csr_addr),
  .csr_ena_o(exe_csr_ena),
  .csr_op_o(exe_csr_op),
  .csr_mode_o(exe_csr_mode),
  .putch_en_o(exe_putch_en),
  .a0_o(exe_a0),
  .ecall_o(exe_ecall),
  .mret_o(exe_mret),
  //.time_intr_o(exe_time_intr),
  .time_intr_firstdetect_o(exe_time_intr_firstdetect)
);

//exe_stage_out
wire exe_rd_w_ena;
wire [4 : 0]exe_rd_w_addr;
wire [4 : 0]exe_inst_type;
wire exe_l_mem;
wire exe_s_mem;
wire [1:0]exe_datasize;
wire exe_unsigned_load;
wire [`REG_BUS]exe_rs2_data;
wire [`REG_BUS]exe_alu_result;
wire [31:0] exe_inst;
wire [`REG_BUS]exe_pc;
wire [11:0]exe_csr_addr;
wire exe_csr_ena;
wire [`REG_BUS]exe_csr_op;
wire [1:0]exe_csr_mode;
wire exe_putch_en;
wire [7:0]exe_a0;
wire exe_ecall;
wire exe_mret;
//wire exe_time_intr;
wire exe_time_intr_firstdetect;
//wire [`REG_BUS]exe_next_pc;



//exe_stage -> mem_stage
reg exe_mem_rd_w_ena;
reg [4 : 0]exe_mem_rd_w_addr;
reg [4 : 0]exe_mem_inst_type;
reg exe_mem_l_mem;
reg exe_mem_s_mem;
reg [1:0]exe_mem_datasize;
reg exe_mem_unsigned_load;
reg [`REG_BUS]exe_mem_rs2_data;
reg [`REG_BUS]exe_mem_alu_result;
reg [31:0] exe_mem_inst;
reg [`REG_BUS]exe_mem_pc;
reg [11:0]exe_mem_csr_addr;
reg exe_mem_csr_ena;
reg [`REG_BUS]exe_mem_csr_op;
reg [1:0]exe_mem_csr_mode;
reg exe_mem_putch_en;
reg [7:0]exe_mem_a0;
reg exe_mem_ecall;
reg exe_mem_mret;
//reg exe_mem_time_intr;
reg exe_mem_time_intr_firstdetect;
//reg [`REG_BUS]exe_mem_next_pc;
always @(posedge clock) begin
  if (reset == 1'b1) begin
    exe_mem_rd_w_ena<=1'b0;
    exe_mem_rd_w_addr<=5'b00000;
    exe_mem_inst_type<=5'b00000;
    exe_mem_l_mem<=1'b0;
    exe_mem_s_mem<=1'b0;
    exe_mem_datasize<=2'b00;
    exe_mem_unsigned_load<=1'b0;
    exe_mem_rs2_data<=`ZERO_WORD;
    exe_mem_alu_result<=`ZERO_WORD;
    exe_mem_inst<=32'b0;
    exe_mem_pc<=PC_START_RESET;
    exe_mem_csr_addr<=12'b000000000000;
    exe_mem_csr_ena<=1'b0;
    exe_mem_csr_op<=`ZERO_WORD;
    exe_mem_csr_mode<=2'b00;
    exe_mem_putch_en<=1'b0;
    exe_mem_a0<=8'b0;
    exe_mem_ecall<=1'b0;
    exe_mem_mret<=1'b0;
    //exe_mem_time_intr<=1'b0;
    exe_mem_time_intr_firstdetect<=1'b0;
    //exe_mem_next_pc<=PC_START_RESET;
  end
  else if (axi_stall == 1'b1) begin
    exe_mem_rd_w_ena<=exe_mem_rd_w_ena;
    exe_mem_rd_w_addr<=exe_mem_rd_w_addr;
    exe_mem_inst_type<=exe_mem_inst_type;
    exe_mem_l_mem<=exe_mem_l_mem;
    exe_mem_s_mem<=exe_mem_s_mem;
    exe_mem_datasize<=exe_mem_datasize;
    exe_mem_unsigned_load<=exe_mem_unsigned_load;
    exe_mem_rs2_data<=exe_mem_rs2_data;
    exe_mem_alu_result<=exe_mem_alu_result;
    exe_mem_inst<=exe_mem_inst;
    exe_mem_pc<=exe_mem_pc;
    exe_mem_csr_addr<=exe_mem_csr_addr;
    exe_mem_csr_ena<=exe_mem_csr_ena;
    exe_mem_csr_op<=exe_mem_csr_op;
    exe_mem_csr_mode<=exe_mem_csr_mode;
    exe_mem_putch_en<=exe_mem_putch_en;
    exe_mem_a0<=exe_mem_a0;
    exe_mem_ecall<=exe_mem_ecall;
    exe_mem_mret<=exe_mem_mret;
    //exe_mem_time_intr<=exe_mem_time_intr;
    exe_mem_time_intr_firstdetect<=exe_mem_time_intr_firstdetect;
    //exe_mem_next_pc<=exe_mem_next_pc;
  end
  else begin
    exe_mem_rd_w_ena<=exe_rd_w_ena;
    exe_mem_rd_w_addr<=exe_rd_w_addr;
    exe_mem_inst_type<=exe_inst_type;
    exe_mem_l_mem<=exe_l_mem;
    exe_mem_s_mem<=exe_s_mem;
    exe_mem_datasize<=exe_datasize;
    exe_mem_unsigned_load<=exe_unsigned_load;
    exe_mem_rs2_data<=exe_rs2_data;
    exe_mem_alu_result<=exe_alu_result;
    exe_mem_inst<=exe_inst;
    exe_mem_pc<=exe_pc;
    exe_mem_csr_addr<=exe_csr_addr;
    exe_mem_csr_ena<=exe_csr_ena;
    exe_mem_csr_op<=exe_csr_op;
    exe_mem_csr_mode<=exe_csr_mode;
    exe_mem_putch_en<=exe_putch_en;
    exe_mem_a0<=exe_a0;
    exe_mem_ecall<=exe_ecall;
    exe_mem_mret<=exe_mret;
    //exe_mem_time_intr<=exe_time_intr;
    exe_mem_time_intr_firstdetect<=exe_time_intr_firstdetect;
    //exe_mem_next_pc<=exe_next_pc;
  end
  
end

////////////////mem_stage////////////////
mem_stage Mem_stage(
  //input
  .rst(reset),
  .inst_type_i(exe_mem_inst_type),
  .rd_w_ena_i(exe_mem_rd_w_ena),
  .rd_w_addr_i(exe_mem_rd_w_addr),
  .l_mem_i(exe_mem_l_mem),
  .s_mem_i(exe_mem_s_mem),
  .datasize_i(exe_mem_datasize),
  .unsigned_load_i(exe_mem_unsigned_load),
  .rs2_data_i(exe_mem_rs2_data),
  .alu_result_i(exe_mem_alu_result),
  .inst_i(exe_mem_inst),
  .pc_i(exe_mem_pc),
  //.next_pc_i(exe_mem_next_pc),
  .csr_addr_i(exe_mem_csr_addr),
  .csr_ena_i(exe_mem_csr_ena),
  .csr_op_i(exe_mem_csr_op),
  .csr_mode_i(exe_mem_csr_mode),
  .putch_en_i(exe_mem_putch_en),
  .a0_i(exe_mem_a0),
  .ecall_i(exe_mem_ecall),
  .mret_i(exe_mem_mret),
  //.time_intr_i(exe_mem_time_intr),
  .time_intr_firstdetect_i(exe_mem_time_intr_firstdetect),

  //from ram
  .data_loaded(data_loaded_origin),
  .data_valid(data_valid_origin),
  .mmio_valid_i(mmio_valid),

  //output
  //to ram
  .mem_valid(mem_valid_origin),
  .datasize_2ram(mem_size_origin),
  .load_en_2ram(mem_load_en_origin),
  .save_en_2ram(mem_save_en_origin),
  .data_2ram(mem_data_origin),
  .addr_2ram(mem_addr_origin),

  //result
  .rd_w_data(mem_rd_w_data),
  //pass
  .inst_type_o(mem_inst_type),
  .rd_w_ena_o(mem_rd_w_ena),
  .rd_w_addr_o(mem_rd_w_addr),
  .inst_o(mem_inst),
  .pc_o(mem_pc),
  //.next_pc_o(mem_next_pc),
  .csr_addr_o(mem_csr_addr),
  .csr_ena_o(mem_csr_ena),
  .csr_op_o(mem_csr_op),
  .csr_mode_o(mem_csr_mode),
  .putch_en_o(mem_putch_en),
  .a0_o(mem_a0),
  .ecall_o(mem_ecall),
  .mret_o(mem_mret),
  //.time_intr_o(mem_time_intr),
  .time_intr_firstdetect_o(mem_time_intr_firstdetect),
  .mmio_valid_o(mem_mmio_valid)
);


////mem_stage_out
wire [`REG_BUS]mem_rd_w_data;
wire [4 : 0]mem_inst_type;
wire mem_rd_w_ena;
wire [4 : 0]mem_rd_w_addr;
wire [31:0]mem_inst;
wire [`REG_BUS]mem_pc;
wire [11:0]mem_csr_addr;
wire mem_csr_ena;
wire [`REG_BUS]mem_csr_op;
wire [1:0]mem_csr_mode;
wire mem_putch_en;
wire [7:0]mem_a0;
wire mem_ecall;
wire mem_mret;
//wire mem_time_intr;
wire mem_time_intr_firstdetect;
//wire [`REG_BUS]mem_next_pc;
wire mem_mmio_valid;



////mem_stage -> wb_stage
reg [`REG_BUS]mem_wb_rd_w_data;
reg [4 : 0]mem_wb_inst_type;
reg mem_wb_rd_w_ena;
reg [4 : 0]mem_wb_rd_w_addr;
reg [31:0]mem_wb_inst;
reg [`REG_BUS]mem_wb_pc;
reg [11:0]mem_wb_csr_addr;
reg mem_wb_csr_ena;
reg [`REG_BUS]mem_wb_csr_op;
reg [1:0]mem_wb_csr_mode;
reg mem_wb_putch_en;
reg [7:0]mem_wb_a0;
reg mem_wb_ecall;
reg mem_wb_mret;
//reg mem_wb_time_intr;
reg mem_wb_time_intr_firstdetect;
//reg [`REG_BUS]mem_wb_next_pc;
reg mem_wb_mmio_valid;

always @(posedge clock) begin
  if ((reset == 1'b1)||(axi_stall == 1'b1))  begin
    mem_wb_rd_w_ena <= 1'b0;
    mem_wb_rd_w_addr <= 5'b00000;
    mem_wb_inst_type <= 5'b00000;
    mem_wb_rd_w_data <= `ZERO_WORD;
    mem_wb_inst<=32'b0;
    mem_wb_pc<=PC_START_RESET;
    //mem_wb_next_pc<=PC_START_RESET;
    mem_wb_csr_addr<=12'b000000000000;
    mem_wb_csr_ena<=1'b0;
    mem_wb_csr_op<=`ZERO_WORD;
    mem_wb_csr_mode<=2'b00;
    mem_wb_putch_en<=1'b0;
    mem_wb_a0<=8'b0;
    mem_wb_ecall<=1'b0;
    mem_wb_mret<=1'b0;
    //mem_wb_time_intr<=1'b0;
    mem_wb_time_intr_firstdetect<=1'b0;
    mem_wb_mmio_valid<=1'b0;
  end
  else begin
    mem_wb_rd_w_ena <= mem_rd_w_ena;
    mem_wb_rd_w_addr <= mem_rd_w_addr;
    mem_wb_inst_type <= mem_inst_type;
    mem_wb_rd_w_data <= mem_rd_w_data; 
    mem_wb_inst<=mem_inst;
    mem_wb_pc<=mem_pc; 
    //mem_wb_next_pc<=mem_next_pc; 
    mem_wb_csr_addr<=mem_csr_addr;
    mem_wb_csr_ena<=mem_csr_ena;
    mem_wb_csr_op<=mem_csr_op;
    mem_wb_csr_mode<=mem_csr_mode;
    mem_wb_putch_en<=mem_putch_en;
    mem_wb_a0<=mem_a0;
    mem_wb_ecall<=mem_ecall;
    mem_wb_mret<=mem_mret;
    //mem_wb_time_intr<=mem_time_intr;
    mem_wb_time_intr_firstdetect<=mem_time_intr_firstdetect;
    mem_wb_mmio_valid<=mem_mmio_valid;
  end

end

////////////////wb_stage////////////////
wb_stage Wb_stage(
  .rst(reset),
  .inst_type_i(mem_wb_inst_type),
  .rd_w_ena_i(mem_wb_rd_w_ena),
  .rd_w_addr_i(mem_wb_rd_w_addr),
  .rd_w_data_i(mem_wb_rd_w_data),
  .inst_i(mem_wb_inst),
  .pc_i(mem_wb_pc),
  //.next_pc_i(mem_wb_next_pc),
  .csr_addr_i(mem_wb_csr_addr),
  .csr_ena_i(mem_wb_csr_ena),
  .csr_op_i(mem_wb_csr_op),
  .csr_mode_i(mem_wb_csr_mode),
  .putch_en_i(mem_wb_putch_en),
  .a0_i(mem_wb_a0),
  .ecall_i(mem_wb_ecall),
  .mret_i(mem_wb_mret),
  //.time_intr_i(mem_wb_time_intr),
  .time_intr_firstdetect_i(mem_wb_time_intr_firstdetect),
  .mmio_valid_i(mem_wb_mmio_valid),

  //from CSRs
  .csr_r_data_i(csrs_csr_r_data),

  //to CSRs
	.csr_w_addr_o(wb_csr_w_addr),
	.csr_w_data_o(wb_csr_w_data),
	.csr_w_ena_o(wb_csr_w_ena),
	.csr_r_addr_o(wb_csr_r_addr),
	.csr_r_ena_o(wb_csr_r_ena),

  //to regfile
  .rd_w_ena_o(wb_rd_w_ena),
  .rd_w_addr_o(wb_rd_w_addr),
  .rd_w_data_o(wb_rd_w_data),
  
  //pass
  .inst_type_o(),
  .inst_o(wb_inst),
  .pc_o(wb_pc),
  //.next_pc_o(wb_next_pc),
  .csr_addr_o(wb_csr_addr),
  .putch_en_o(putch_en),
  .a0_o(),
  .ecall_o(wb_ecall),
  .mret_o(wb_mret),
  //.time_intr_o(wb_time_intr),
  .time_intr_firstdetect_o(wb_time_intr_firstdetect),
  .mmio_valid_o(wb_mmio_valid)
);

////wb_stage_out
wire wb_rd_w_ena;
wire [4 : 0]wb_rd_w_addr;
wire [4 : 0]wb_inst_type;
wire [`REG_BUS]wb_rd_w_data;
wire [31:0]wb_inst;
wire [`REG_BUS]wb_pc;
//wire [`REG_BUS]wb_next_pc;
wire wb_mmio_valid;

wire wb_csr_r_ena;
wire [11:0]wb_csr_r_addr;
wire wb_csr_w_ena;
wire [11:0]wb_csr_w_addr;
wire [`REG_BUS]wb_csr_w_data;
wire [11:0]wb_csr_addr;

//interruption
wire wb_ecall;
wire wb_mret;
//wire wb_time_intr;   //signal that indicate a interruption should be raised from id
wire wb_time_intr_firstdetect;   //signal that raise a interruption from wb to csrs
wire csrs_mstatus_mie;
wire csrs_mie_mtie;
wire clint_raise_interruption;
wire time_interruption_confirmation;
wire ecall_en;
wire mret_en;
assign ecall_en = (csrs_mstatus_mie == 1'b1)? wb_ecall : 0;
assign mret_en = wb_mret;
assign time_interruption_confirmation = csrs_mstatus_mie && csrs_mie_mtie && clint_raise_interruption;
//wire time_intr_firstdetect;
//assign time_intr_firstdetect = (id_exe_time_intr == 1'b1) && (exe_mem_time_intr == 1'b0) && (mem_wb_time_intr == 1'b0);


//csrs ==> wb
wire [`REG_BUS]csrs_csr_r_data;

////////////////register////////////////
regfile Regfile(
  .clk(clock),
  .rst(reset),
  .w_addr(wb_rd_w_addr),
  .w_data(wb_rd_w_data),
  .w_ena(wb_rd_w_ena),
  
  .r_addr1(rs1_r_addr),
  .r_data1(r_data1),
  .r_ena1(rs1_r_ena),
  .r_addr2(rs2_r_addr),
  .r_data2(r_data2),
  .r_ena2(rs2_r_ena),

  .regs_o(regs),

  .a0(chara)
);

////////////////CSRs////////////////
csrs csrs(
  .clk(clock),
	.rst(reset),

  .ecall_en(ecall_en),
  .mret_en(mret_en),
  .time_intr_en(wb_time_intr_firstdetect),
  .wb_pc(wb_pc),
  //.wb_next_pc(wb_next_pc),
  .clint_raise_interruption(clint_raise_interruption),
  .mtvec_dest(mtvec_dest),
  .mepc_dest(mepc_dest),
  .mstatus_mie(csrs_mstatus_mie),
  .mie_mtie(csrs_mie_mtie),

  //difftest
  .mstatus_o(csrs_mstatus),
  .sstatus_o(csrs_sstatus),
  .mtvec_o(csrs_mtvec),
  .mepc_o(csrs_mepc),
  .mcause_o(csrs_mcause),
  .mip_o(csrs_mip),
  .mie_o(csrs_mie),
  .mscratch_o(csrs_mscratch),
	
	.csr_w_addr(wb_csr_w_addr),
	.csr_w_data(wb_csr_w_data),
	.csr_w_ena(wb_csr_w_ena),
	.csr_r_addr(wb_csr_r_addr),
	.csr_r_ena(wb_csr_r_ena),

  .csr_r_data(csrs_csr_r_data)
);



// Difftest
reg cmt_wen;
reg [7:0] cmt_wdest;
reg [`REG_BUS] cmt_wdata;
reg [`REG_BUS] cmt_pc;
reg [31:0] cmt_inst;
reg cmt_valid;
reg trap;
reg [7:0] trap_code;
reg [63:0] cycleCnt;
reg [63:0] instrCnt;
reg [`REG_BUS] regs_diff [0 : 31];
reg [11:0]cmt_csr_addr;
reg cmt_time_intr_firstdetect;
reg cmt_wb_mmio_valid;



wire [`REG_BUS] csrs_mstatus;
wire [`REG_BUS] csrs_mtvec;
wire [`REG_BUS] csrs_mepc;
wire [`REG_BUS] csrs_mcause;
wire [`REG_BUS] csrs_mip;
wire [`REG_BUS] csrs_mie;
wire [`REG_BUS] csrs_mscratch;
wire [`REG_BUS] csrs_sstatus;
/*
reg [`REG_BUS] mstatus_diff;
reg [`REG_BUS] mtvec_diff;
reg [`REG_BUS] mepc_diff;
reg [`REG_BUS] mcause_diff;
always @(posedge clock) begin
  mstatus_diff <= csrs_mstatus;
  mtvec_diff<=csrs_mtvec;
  mepc_diff<=csrs_mepc;
  mcause_diff<=csrs_mcause;
end */

//wire inst_valid = (wb_pc != PC_START_RESET) && (wb_inst != 0) && (wb_time_intr_firstdetect != 1'b1);// && (wb_inst != 32'h7b);
wire inst_valid = (wb_inst != 0) && (wb_time_intr_firstdetect != 1'b1);// && (wb_inst != 32'h7b);
wire skip = cmt_valid && ((cmt_inst == 32'h7b) || (cmt_csr_addr == 12'hb00) || (cmt_wb_mmio_valid==1'b1));


always @(posedge clock) begin
  if (reset) begin
    {cmt_wen, cmt_wdest, cmt_wdata, cmt_pc, cmt_inst, cmt_valid, trap, trap_code, cycleCnt, instrCnt} <= 0;
  end
  else if (~trap) begin
    cmt_wen <= wb_rd_w_ena;
    cmt_wdest <= {3'd0, wb_rd_w_addr};
    cmt_wdata <= wb_rd_w_data;
    cmt_pc <= wb_pc;
    cmt_inst <= wb_inst;
    cmt_valid <= inst_valid;
    cmt_csr_addr<=wb_csr_addr;
    cmt_time_intr_firstdetect<=wb_time_intr_firstdetect;
    cmt_wb_mmio_valid<=wb_mmio_valid;

		regs_diff <= regs;

    trap <= wb_inst[6:0] == 7'h6b;
    trap_code <= regs[10][7:0];
    cycleCnt <= cycleCnt + 1;
    if (inst_valid == 1'b1) begin
      instrCnt <= instrCnt + 1;
    end
    else begin
      instrCnt <= instrCnt + 0;
    end
    //instrCnt <= instrCnt + inst_valid;
  end
end

DifftestInstrCommit DifftestInstrCommit(
  .clock              (clock),
  .coreid             (0),
  .index              (0),
  .valid              (cmt_valid),
  .pc                 (cmt_pc),
  .instr              (cmt_inst),
  .skip               (skip),
  .isRVC              (0),
  .scFailed           (0),
  .wen                (cmt_wen),
  .wdest              (cmt_wdest),
  .wdata              (cmt_wdata)
  //.special            (0)
);

wire [`REG_BUS]exceptionPC;
wire [31:0]exceptionInst;
wire [31:0]intrNO;
assign exceptionPC = (cmt_time_intr_firstdetect == 1'b1)? cmt_pc : 0;
assign exceptionInst = (cmt_time_intr_firstdetect == 1'b1)? cmt_inst : 0;
assign intrNO = (cmt_time_intr_firstdetect == 1'b1)? 32'h7 : 0;

DifftestArchEvent DifftestArchEvent(
  .clock              (clock),
  .coreid             (0),
  .intrNO             (intrNO),
  .cause              (0),
  .exceptionPC        (exceptionPC)
  //.exceptionInst      (exceptionInst)
);



DifftestArchIntRegState DifftestArchIntRegState (
  .clock              (clock),
  .coreid             (0),
  .gpr_0              (regs_diff[0]),
  .gpr_1              (regs_diff[1]),
  .gpr_2              (regs_diff[2]),
  .gpr_3              (regs_diff[3]),
  .gpr_4              (regs_diff[4]),
  .gpr_5              (regs_diff[5]),
  .gpr_6              (regs_diff[6]),
  .gpr_7              (regs_diff[7]),
  .gpr_8              (regs_diff[8]),
  .gpr_9              (regs_diff[9]),
  .gpr_10             (regs_diff[10]),
  .gpr_11             (regs_diff[11]),
  .gpr_12             (regs_diff[12]),
  .gpr_13             (regs_diff[13]),
  .gpr_14             (regs_diff[14]),
  .gpr_15             (regs_diff[15]),
  .gpr_16             (regs_diff[16]),
  .gpr_17             (regs_diff[17]),
  .gpr_18             (regs_diff[18]),
  .gpr_19             (regs_diff[19]),
  .gpr_20             (regs_diff[20]),
  .gpr_21             (regs_diff[21]),
  .gpr_22             (regs_diff[22]),
  .gpr_23             (regs_diff[23]),
  .gpr_24             (regs_diff[24]),
  .gpr_25             (regs_diff[25]),
  .gpr_26             (regs_diff[26]),
  .gpr_27             (regs_diff[27]),
  .gpr_28             (regs_diff[28]),
  .gpr_29             (regs_diff[29]),
  .gpr_30             (regs_diff[30]),
  .gpr_31             (regs_diff[31])
);

DifftestTrapEvent DifftestTrapEvent(
  .clock              (clock),
  .coreid             (0),
  .valid              (trap),
  .code               (trap_code),
  .pc                 (cmt_pc),
  .cycleCnt           (cycleCnt),
  .instrCnt           (instrCnt)
);

DifftestCSRState DifftestCSRState(
  .clock              (clock),
  .coreid             (0),
  .priviledgeMode     (`RISCV_PRIV_MODE_M),
  .mstatus            (csrs_mstatus),
  .sstatus            (csrs_sstatus),
  .mepc               (csrs_mepc),
  .sepc               (0),
  .mtval              (0),
  .stval              (0),
  .mtvec              (csrs_mtvec),
  .stvec              (0),
  .mcause             (csrs_mcause),
  .scause             (0),
  .satp               (0),
  .mip                (csrs_mip),
  .mie                (csrs_mie),
  .mscratch           (csrs_mscratch),
  .sscratch           (0),
  .mideleg            (0),
  .medeleg            (0)
);

DifftestArchFpRegState DifftestArchFpRegState(
  .clock              (clock),
  .coreid             (0),
  .fpr_0              (0),
  .fpr_1              (0),
  .fpr_2              (0),
  .fpr_3              (0),
  .fpr_4              (0),
  .fpr_5              (0),
  .fpr_6              (0),
  .fpr_7              (0),
  .fpr_8              (0),
  .fpr_9              (0),
  .fpr_10             (0),
  .fpr_11             (0),
  .fpr_12             (0),
  .fpr_13             (0),
  .fpr_14             (0),
  .fpr_15             (0),
  .fpr_16             (0),
  .fpr_17             (0),
  .fpr_18             (0),
  .fpr_19             (0),
  .fpr_20             (0),
  .fpr_21             (0),
  .fpr_22             (0),
  .fpr_23             (0),
  .fpr_24             (0),
  .fpr_25             (0),
  .fpr_26             (0),
  .fpr_27             (0),
  .fpr_28             (0),
  .fpr_29             (0),
  .fpr_30             (0),
  .fpr_31             (0)
);

endmodule
